package itsm.isperp.module.controller.bpm;

import itsm.isperp.framework.core.context.ContextHolder;
import itsm.isperp.framework.message.MessageUtils;
import itsm.isperp.framework.utils.HibernateUUIDGenerator;
import itsm.isperp.framework.web.controller.BaseController;
import itsm.isperp.framework.web.response.ResultMessage;
import itsm.isperp.module.dto.bpm.BpmNode;
import itsm.isperp.module.dto.bpm.BpmNodeSettingDTO;
import itsm.isperp.module.entity.bpm.BpmNodeSetting;
import itsm.isperp.module.service.bpm.BpmNodeSettingService;
import itsm.isperp.module.service.bpm.act.BpmActService;
import itsm.isperp.workflow.dto.BpmTransitionLine;
import itsm.isperp.workflow.service.BpmProcessDefinitaionService;
import itsm.isperp.workflow.utils.BpmUtils;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.activiti.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
 * 
 * 流程设置控制器
 * 
 * @author lizx
 * @date 2013-7-3
 * 
 */
@Controller
@RequestMapping(value = "bpm/nodeSetting")
public class BpmNodeSettingController extends BaseController<BpmNodeSetting> {

	@Autowired
	BpmNodeSettingService bpmNodeSettingService;

	@Autowired
	BpmActService bpmActService;

	@Override
	public BpmNodeSettingService getService() {
		return bpmNodeSettingService;
	}

	@Override
	public String getPageTitle() {

		return "节点设置";
	}

	@RequestMapping("save")
	@ResponseBody
	@Override
	public ResultMessage save(BpmNodeSetting model, HttpServletRequest req) {

		if (StringUtils.isNotEmpty(model.getStartMessage())) {
			String[] messageTypes = req.getParameterValues("messageTypes");
			if (ArrayUtils.isNotEmpty(messageTypes)) {
				String ms = messageTypes[0];
				for (int i = 1; i < messageTypes.length; i++) {
					ms += "," + messageTypes[i];
				}
				model.setMessageType(ms);
			}
			this.getService().saveOrUpdateAndSpecific(model, req,
					"message_type");
		} else {

			String _canWithdraw = req.getParameter("_canWithdraw");
			if (StringUtils.isNotEmpty(_canWithdraw)) {
				this.getService().saveOrUpdateAndSpecific(model, req,
						"can_withdraw", "can_rollback");
			}
			this.getService().saveOrUpdate(model, req);
		}

		String strLoop = req.getParameter("strLoop");
		if (StringUtils.isNotEmpty(strLoop)) {
			String strComp = req.getParameter("strComp");
			String defId = req.getParameter("defId");
			BpmProcessDefinitaionService bpmProcessDefinitaionService = ContextHolder
					.getSpringBean("bpmProcessDefinitaionService");
			ProcessDefinitionEntity proDefEntity = null;

			proDefEntity = bpmProcessDefinitaionService
					.getProcessDefinitionEntityById(defId);

			String deployId = proDefEntity.getDeploymentId();

			try {
				bpmProcessDefinitaionService
						.updateMultiUserTaskCondition(defId, deployId,
								model.getActNodeId(), strLoop, strComp);
			} catch (Exception e) {

				e.printStackTrace();
			}
		}

		return ResultMessage.newInstance(true, null, model.getId());
	}

	/**
	 * 编辑界面
	 * 
	 * @param id
	 *            唯一标识
	 * @return 编辑视图
	 * @throws DocumentException
	 * @throws UnsupportedEncodingException
	 */
	@Override
	@RequestMapping("edit")
	public ModelAndView edit(String id, HttpServletRequest req)
			throws DocumentException, UnsupportedEncodingException {
		ModelAndView mv = new ModelAndView();

		String bpmProcessSettingId = req.getParameter("bpmProcessSettingId");
		String nodeId = req.getParameter("nodeId");

		String name = req.getParameter("name");
		String type = req.getParameter("type");

		String defId = req.getParameter("processDefinitionId");

		mv.addObject("defKey", defId.split(":")[0]);
		mv.addObject("defId", defId);
		mv.addObject("nodeId", nodeId);

		mv.addObject("name", name);
		// 查询是否存在此节点的数据，如果没有则插入一条新的节点设置数据
		BpmNodeSetting setting = this.getService().findByNodeId(nodeId);
		if (setting == null) {
			setting = new BpmNodeSetting();
			setting.setId(HibernateUUIDGenerator.generate());
			setting.setBpmProcessSettingId(bpmProcessSettingId);
			setting.setActNodeId(nodeId);
			this.getService().saveOrUpdate(setting);
		}
		if(StringUtils.isNotBlank(bpmProcessSettingId))
			setting.setBpmProcessSettingId(bpmProcessSettingId);
		BpmProcessDefinitaionService bpmProcessDefinitaionService = ContextHolder
				.getSpringBean("bpmProcessDefinitaionService");
		ProcessDefinitionEntity proDefEntity = null;
		ActivityImpl curActivity = null;

		List<PvmTransition> outTrans = null;
		// 如果是任务节点则用人物编辑，否则用网关编辑
		switch (type) {
		case "multiUserTask":
		case "userTask":
			mv.setViewName("bpm/nodeSetting/userTaskEdit");
			mv.addObject("messageTypes", MessageUtils.MESSAGE_TYPES);
			setting = new BpmNodeSettingDTO(setting);
			proDefEntity = bpmProcessDefinitaionService
					.getProcessDefinitionEntityById(defId);
			curActivity = proDefEntity.findActivity(nodeId);

			outTrans = curActivity.getOutgoingTransitions();
			List<BpmTransitionLine> lines = new ArrayList<>();
			lines.add(new BpmTransitionLine());
			for (PvmTransition tran : outTrans) {
				Object tname = tran.getProperty("name");
				BpmTransitionLine m = new BpmTransitionLine();
				m.setName(tname == null ? "提交审批" : tname.toString());
				m.setNextTransitionId(tran.getId());

				lines.add(m);
			}

			if (curActivity.getActivityBehavior() instanceof ParallelMultiInstanceBehavior) {
				ParallelMultiInstanceBehavior paralleBehavior = (ParallelMultiInstanceBehavior) curActivity
						.getActivityBehavior();

				try {
					String strLoop = paralleBehavior
							.getLoopCardinalityExpression().getExpressionText();

					mv.addObject("strLoop", strLoop);

				} catch (Exception ex) {
					mv.addObject("strLoop", "");
				}

				try {
					String strComp = paralleBehavior
							.getCompletionConditionExpression()
							.getExpressionText();

					mv.addObject("strComp", strComp);
				} catch (Exception ex) {
					mv.addObject("strComp", "");
				}
			}

			mv.addObject("outLines", lines);
			break;

		case "exclusiveGateway":

			proDefEntity = bpmProcessDefinitaionService
					.getProcessDefinitionEntityById(defId);

			String deployId = proDefEntity.getDeploymentId();

			curActivity = proDefEntity.findActivity(nodeId);

			Map<String, BpmNode> incomeNodes = new HashMap<>();
			Map<String, BpmNode> outcomeNodes = new HashMap<>();

			List<PvmTransition> inTrans = curActivity.getIncomingTransitions();
			for (PvmTransition tran : inTrans) {
				ActivityImpl act = (ActivityImpl) tran.getSource();
				String actId = act.getId();
				if (!incomeNodes.containsKey(actId)) {
					String nodeName = (String) act.getProperty("name");
					String nodeType = (String) act.getProperty("type");
					Boolean isMultiple = Boolean.valueOf(act
							.getProperty("multiInstance") != null);

					incomeNodes.put(actId, new BpmNode(actId, nodeName,
							nodeType, isMultiple));
				}
			}

			String xml = this.bpmActService.getProcessDefinitionXmlByDeployId(
					deployId).toString();

			Map<String, String> conditionMap = BpmUtils.getDecisionConditions(
					xml, nodeId);

			outTrans = curActivity.getOutgoingTransitions();
			for (PvmTransition tran : outTrans) {
				ActivityImpl act = (ActivityImpl) tran.getDestination();
				String actId = tran.getId();
				if (!outcomeNodes.containsKey(actId)) {
					String nodeName = (String) tran.getProperty("name")
							+ "<br>-><label style='color:blue'>"
							+ (String) act.getProperty("name") + "</label>";
					String nodeType = (String) act.getProperty("type");
					Boolean isMultiple = Boolean.valueOf(act
							.getProperty("multiInstance") != null);
					BpmNode bpmNode = new BpmNode(actId, nodeName, nodeType,
							isMultiple);
					String condition = conditionMap.get(actId);
					if (condition != null) {
						bpmNode.setCondition(condition);
					}

					outcomeNodes.put(actId, bpmNode);
				}
			}

			mv.addObject("deployId", deployId);
			mv.addObject("incomeNodes", incomeNodes.values());
			mv.addObject("outcomeNodes", outcomeNodes.values());

			mv.setViewName("bpm/nodeSetting/gateWayEdit");
			return mv;

		case "parallelGateway":
			mv.addObject("msg", "并行网关是自动执行的，不需要进行额外设定！");
			mv.setViewName("bpm/nodeSetting/nodeCannotEdit");
			return mv;

		case "email":
			mv.addObject("messageTypes", MessageUtils.MESSAGE_TYPES);
			setting = new BpmNodeSettingDTO(setting);
			mv.setViewName("bpm/nodeSetting/messageServiceTaskEdit");

			break;

		case "scriptTask":
			mv.addObject("messageTypes", MessageUtils.MESSAGE_TYPES);
			setting = new BpmNodeSettingDTO(setting);
			mv.setViewName("bpm/nodeSetting/bpmNodeScriptEdit");

			break;
		case "startEvent":
			mv.setViewName("bpm/nodeSetting/bpmNodeScriptEdit");
			mv.addObject("messageTypes", MessageUtils.MESSAGE_TYPES);
			setting = new BpmNodeSettingDTO(setting);
			break;
		case "endEvent":
			mv.setViewName("bpm/nodeSetting/bpmNodeScriptEdit");
			mv.addObject("messageTypes", MessageUtils.MESSAGE_TYPES);
			setting = new BpmNodeSettingDTO(setting);
			break;

		case "boundaryEvent":

			// 表示一个编辑事件
			proDefEntity = bpmProcessDefinitaionService
					.getProcessDefinitionEntityById(defId);
			curActivity = proDefEntity.findActivity(nodeId);
			String bType = (String) curActivity.getProperty("type");
			if ("boundaryTimer".equals(bType)) {
				// ActivityImpl pAct = curActivity.getParentActivity();
				// List<TimerDeclarationImpl> timers =
				// (List<TimerDeclarationImpl>) pAct
				// .getProperty("timerDeclarations");
				// TimerDeclarationImpl currTimer = null;
				// Find_Timer: for (TimerDeclarationImpl timer : timers) {
				//
				// if (nodeId.equals(timer.getJobHandlerConfiguration())) {
				// currTimer = timer;
				// break Find_Timer;
				// }
				//
				// }
				//
				// if (currTimer != null) {
				// TimerEntity t = currTimer.prepareTimerEntity(null);
				//
				// System.out.println(t);
				// }

			}

			mv.addObject("msg", "请在流程设计器中编辑，然后重新部署！");
			mv.setViewName("bpm/nodeSetting/nodeCannotEdit");
			return mv;

		default:
			mv.addObject("msg", "此类型请在流程设计器中编辑，然后重新部署！");
			mv.setViewName("bpm/nodeSetting/nodeCannotEdit");

			return mv;
		}

		// 根据流程设定中流程定义的key得到一个的基本配置信息（包括流程名称等）
		mv.addObject("model", setting);
		return mv;
	}
}
